package com.qf.gateway.filter;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qf.gateway.bean.TokenWhiteListUri;
import io.jsonwebtoken.*;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.ByteBufFlux;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 30909
 * 过滤器 请求是否携带 token
 * 如果请求不携带 token ，就拒绝
 * 全局过滤器
 * @author 30909
 */
@Configuration
//这两个注解
@Component
public class TokenFilter implements GlobalFilter, Ordered {

    /**
     * url 白名单
     */
    private List<TokenWhiteListUri> uris = new ArrayList<>();

    /**
     * ↑ 对外界提供的set方法
     */
    public void setUris(List<TokenWhiteListUri> uris) {
        this.uris = uris;
    }

    private boolean inWhiteList(String uri) {
        for (TokenWhiteListUri tokenWhiteListUri : uris) {
            if (tokenWhiteListUri.getUri().equals(uri)) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //拿到请求对象
        ServerHttpRequest request = exchange.getRequest();
        //获取请求头中的token
        List<String> tokens = request.getHeaders().get("token");
        //校验token
        boolean checkToken = true;

        if (tokens != null) {
            if (tokens.size() == 0) {
                checkToken = false;
            }
            //有token
            try {
                String token = tokens.get(0);
                Jwts.parser().setSigningKey("qianfeng".getBytes()).parseClaimsJws(token).getBody();
            } catch (Exception e) {
                e.printStackTrace();
            }
        } else {
            //无 token
            checkToken = false;
        }
        //决定是否放行
        if (!checkToken) {
            //报告401；
            ServerHttpResponse response = exchange.getResponse();
            HttpHeaders headers = response.getHeaders();
            headers.add("Content-Type", "application/json;charset=UTF-8");


            return response.writeAndFlushWith(
                    Flux.just(
                            ByteBufFlux.just(
                                    response.bufferFactory().wrap(getWrapData())
                            )
                    )
            );
        }

//        return chain.filter(exchange);
        return chain.filter(exchange).then(
                Mono.fromRunnable(() -> {
                    //彻底解决其他工厂调用时的跨域问题
                    HttpHeaders headers = exchange.getResponse().getHeaders();
                    //移除六种导致跨域问题的头信息
                    headers.remove("Access-Control-Allow-Credentials");
                    headers.remove("Access-Control-Allow-Origin");
                    headers.remove("Access-Control-Allow-Methods");
                    headers.remove("Access-Control-Max-Age");
                    headers.remove("Access-Control-Allow-Headers");
                    headers.remove("Access-Control-Expose-Headers");
                    //添加不能导致跨域错误的头信息
                    headers.add("Access-Control-Allow-Credentials", "true");
                    headers.add("Access-Control-Allow-Origin", "*");
                    headers.add("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS");
                    headers.add("Access-Control-MAX-Age", "3600");
                    headers.add("Access-Control-Allow-Headers", "Origin,X-request-With,Content-Type,Accept");
                    headers.add("Access-Control-Expose-Headrs", "Location");
                })
        );
    }

    /**
     * @return Spring中提供了一个Ordered接口。从单词意思就知道Ordered接口的作用就是用来排序的。
     * Spring框架是一个大量使用策略设计模式的框架，这意味着有很多相同接口的实现类，那
     * 么必定会有优先级的问题。于是Spring就提供了Ordered这个接口，来处
     * 理相同接口实现类的优先级问题。
     */
    @Override
    public int getOrder() {
        return 1;
    }

    /**
     * 封装身份不合法
     */
    private byte[] getWrapData() {
        Map<String, String> maps = new HashMap<>();
        maps.put("code", "401");
        maps.put("msg", "请使用一个有效的 token ");
        maps.put("result", null);
        try {
            return new ObjectMapper().writeValueAsString(maps).getBytes();
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return "".getBytes();
    }
}
